using System;
using System.Linq;

namespace Crap4Net
{
    public class MethodSignature : IEquatable<MethodSignature>
    {
        public MethodSignature(string assemblyName, 
            string nameSpace, 
            string typeName, 
            string methodName, 
            string[] signature)
        {
            if (String.IsNullOrEmpty(assemblyName))
                throw new ArgumentException("assemblyName is null or empty.", "assemblyName");
            if (nameSpace==null)
                throw new ArgumentException("assemblyName is null.", "nameSpace");
            if (String.IsNullOrEmpty(typeName))
                throw new ArgumentException("typeName is null or empty.", "typeName");
            if (String.IsNullOrEmpty(methodName))
                throw new ArgumentException("methodName is null or empty.", "methodName");
            if (signature==null)
                throw new ArgumentException("Signature is null.", "Signature");
            AssemblyName = assemblyName;
        		Namespace = nameSpace;
        		TypeName = typeName;
        		MethodName = methodName;
        		Signature = signature;
        }

        public string AssemblyName { get; private set; }
        public string Namespace { get; private set; }
        public string TypeName { get; private set; }
        public string MethodName { get; private set; }
        public string[] Signature { get; private set; }
        //public string ReturnValue { get; private set; }

        public string FullName
        {
            get
            {
                return string.Format("{0}.{1}.{2}({3})", Namespace, TypeName, MethodName, SignatureString, AssemblyName);
            }
        }
        public string SignatureString
        {
            get
            {
                if (Signature.Length == 0)
                    return "";

                var sigString = "";
                for (int i = 0; i < Signature.Length-1; i++)
                {
                    sigString += Signature[i] + ",";
                }
                sigString  += Signature[Signature.Length-1];
                return sigString;
            }
        }
        public override string ToString()
        {
            var sigString = "";
            foreach (var param in Signature)
            {
                sigString += param + ",";
            }
            return string.Format("{4}: {0}.{1}.{2}({3})",Namespace,TypeName,MethodName,sigString,AssemblyName);
        }
        
        #region IEquatable<MethodSignature> Members

        public bool Equals(MethodSignature other)
        {
            if (null == other)
            {

                return false;
            }
            if (!IsGenericMethod())
            {
                return AssemblyName.Equals(other.AssemblyName) &&
                    Namespace.Equals(other.Namespace) &&
                    TypeName.Equals(other.TypeName) &&
                    MethodName.Equals(other.MethodName) &&
                    Signature.SequenceEqual(other.Signature);
            }
            else
            {
                var myStrippedName = MethodName.Split(new char[] { '<' })[0];
                int myNumOfgenericArguemtns = GetNumberOfGenericArguments();
                var otherStrippedName = other.MethodName.Split(new char[] { '<' })[0];
                int otherNumOfgenericArguemtns = other.GetNumberOfGenericArguments();
                return AssemblyName.Equals(other.AssemblyName) &&
                    Namespace.Equals(other.Namespace) &&
                    TypeName.Equals(other.TypeName) &&
                    myStrippedName.Equals(otherStrippedName) &&
                    myNumOfgenericArguemtns.Equals(otherNumOfgenericArguemtns) &&
                    Signature.SequenceEqual(other.Signature);
            }
        }

        public override bool Equals(object other)
        {
            return Equals(other as MethodSignature);
        }
        private bool IsGenericMethod()
        {
            return MethodName.Contains("<");
        }
        private int GetNumberOfGenericArguments()
        {
            var parts = MethodName.Split(new char[] { '<' });
            if (parts.Length < 2)
                return 0;
            return parts[1].Split(new char[] { ',' }).Length;
        }
        #endregion
    }
}
